use std::{rc::Rc, cell::RefCell, sync::Arc};

use crate::{instructions::base::{Instruction, BytecodeReader, self}, rtda::Frame};

// 给类的某个静态变量赋值，它需要两个操作数。第一个操作数是uint16索引，来自字节码。
// 通过这个索引可以从当前类的运行时常量池中找到一个字段符号引用，解析这个符号引用就可以知道要给类的哪个静态变量赋值。
// 第二个操作数是要赋给静态变量的值，从操作数栈中弹出。

#[derive(Debug, Default)]
pub struct PUT_STATIC {
    index: usize
}

impl Instruction for PUT_STATIC {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.index = reader.read_u16() as usize;
    }

    // 某个静态变量赋值
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let current_method = frame.borrow().get_method();
        let current_class = current_method.get_class();
        let cp = current_class.get_constant_pool().unwrap();
        let field_ref = cp.get_constant(self.index).unwrap().field_ref();
        // if let Constant::FieldRef(class_ref) = constant {
        let field = field_ref.lock().unwrap().resolved_field();
        let class = field.get_class();
        // init class
        if !class.init_started() {
            // 获取到此锁可进行初始化。
            let init_lock = class.get_init_lock();
            let _lock = init_lock.lock().unwrap();
            // TODO 231028 不清楚为什么不直接往下执行，而是在执行一次此指令，后续测试。
            // 当前帧的nextPC字段已经指向下一条指令，所以需要修改nextPC，让它重新指向当前指令。
            frame.borrow_mut().revert_next_pc();
            // 再次判断，若在其他线程初始化后获取到锁则跳过初始化
            if !class.init_started() {
                base::init_class(frame.borrow().get_thread(), class);
            }
            return;
        }

        // 非静态字段，抛出异常
        if !field.is_static() {
            panic!("java.lang.IncompatibleClassChangeError")
        }
        // final字段即为静态常量，只能在当前类初始化时赋值
        if field.is_final() {
            if !Arc::ptr_eq(&current_class, &class) || current_method.get_name() != "<clinit>" {
                panic!("java.lang.IllegalAccessError")
            }
        }
        let descriptor = field.get_descriptor();
        let slot_id = field.get_slot_id();
        let slots = class.get_static_vars();
        let stack = frame.borrow().get_operand_stack();
        // 从操作数栈中弹出相应的值，然后赋给静态变量。
        match &descriptor[..1] {
            "Z" | "B"  | "C" | "S" | "I" => slots.write().unwrap().set_int(slot_id, stack.borrow_mut().pop_int()),
            "F" => slots.write().unwrap().set_float(slot_id, stack.borrow_mut().pop_float()),
            "J" => slots.write().unwrap().set_long(slot_id, stack.borrow_mut().pop_long()),
            "D" => slots.write().unwrap().set_double(slot_id, stack.borrow_mut().pop_double()),
            "L" | "[" => slots.write().unwrap().set_ref(slot_id, stack.borrow_mut().pop_ref()),
            _ => ()
        }
    }


}
